package com.ticket.system.service.impl;

import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.google.common.base.Joiner;
import com.google.common.base.Splitter;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Maps;
import com.google.common.collect.Table;
import com.ticket.common.constant.CacheConstants;
import com.ticket.common.constant.PerformConstants;
import com.ticket.common.core.domain.AjaxResult;
import com.ticket.common.core.domain.model.LoginUser;
import com.ticket.common.core.redis.RedisCache;
import com.ticket.common.exception.ServiceException;
import com.ticket.common.exception.base.BaseException;
import com.ticket.common.utils.Const;
import com.ticket.common.utils.DateUtils;
import com.ticket.common.utils.SecurityUtils;
import com.ticket.common.utils.StringUtils;
import com.ticket.system.domain.TYanchuReservedTicket;
import com.ticket.system.domain.YanchuSeat;
import com.ticket.system.domain.YanchuSession;
import com.ticket.system.domain.YanchuTicketPrice;
import com.ticket.system.domain.vo.*;
import com.ticket.system.mapper.TYanchuReservedTicketMapper;
import com.ticket.system.mapper.YanchuSeatMapper;
import com.ticket.system.mapper.YanchuSessionMapper;
import com.ticket.system.mapper.YanchuTicketPriceMapper;
import com.ticket.system.service.ITYanchuReservedTicketService;
import com.ticket.system.service.IYanchuTicketPriceService;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.compress.utils.Lists;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 场次价格Service业务层处理
 * 
 * @author ruoyi
 * @date 2023-09-27
 */
@Service
public class YanchuTicketPriceServiceImpl implements IYanchuTicketPriceService 
{
    private static final Logger logger = LoggerFactory.getLogger(YanchuTicketPriceServiceImpl.class);
    @Autowired
    private YanchuTicketPriceMapper yanchuTicketPriceMapper;

    @Autowired
    private RedisCache redisCache;
    @Autowired
    private YanchuSeatMapper yanchuSeatMapper;
    @Autowired
    private ITYanchuReservedTicketService yanchuReservedTicketService;
    @Autowired
    private YanchuSessionMapper yanchuSessionMapper;
    @Autowired
    private TYanchuReservedTicketMapper yanchuReservedTicketMapper;


    /**
     * 查询场次价格
     * 
     * @param id 场次价格主键
     * @return 场次价格
     */
    @Override
    public YanchuTicketPrice selectYanchuTicketPriceById(Long id)
    {
        return yanchuTicketPriceMapper.selectYanchuTicketPriceById(id);
    }

    /**
     * 查询场次价格列表
     * 
     * @param yanchuTicketPrice 场次价格
     * @return 场次价格
     */
    @Override
    public List<YanchuTicketPrice> selectYanchuTicketPriceList(YanchuTicketPrice yanchuTicketPrice)
    {
        return yanchuTicketPriceMapper.selectYanchuTicketPriceList(yanchuTicketPrice);
    }

    @Override
    public List<PriceVo> selectTicketPriceVoList(Long sessionId)
    {
        List<PriceVo> listVo = redisCache.getCacheObject(CacheConstants.TICKET_PRICE_LIST_KEY+sessionId);
        if(CollectionUtils.isNotEmpty(listVo)){
            return listVo;
        }
        listVo = new ArrayList<>();
        PriceVo vo = null;
        List<YanchuTicketPrice> list = yanchuTicketPriceMapper.selectProgPriceList(sessionId);
        if(CollectionUtils.isNotEmpty(list)){
            List<Long> priceIds = list.stream().map(YanchuTicketPrice::getId).collect(Collectors.toList());
            //是否存在已售罄
            List<Long> onPriceIds = new ArrayList<>();
            List<YanchuSeat> yanchuSeats = yanchuSeatMapper.selectYanchuSeatListByPriceIds(priceIds);
            if (CollectionUtils.isNotEmpty(yanchuSeats)){
                onPriceIds = yanchuSeats.stream().map(YanchuSeat::getPriceId).distinct().collect(Collectors.toList());
            }
            for(YanchuTicketPrice price:list){
                vo = new PriceVo();
                vo.setPrice(price.getSalePrice().toPlainString());
                vo.setPriceId(price.getId());
                vo.setColor(price.getColor());
                vo.setTitle(price.getTitle());
                vo.setSeats(price.getSeats());
                if (CollectionUtils.isNotEmpty(onPriceIds)){
                    if (onPriceIds.contains(price.getId())){
                        vo.setIsSalable(Const.ONE);
                    }else {
                        vo.setIsSalable(Const.TWO);
                    }
                }else {
                    vo.setIsSalable(Const.TWO);
                }
                listVo.add(vo);
            }
            //一小时有效
            redisCache.setCacheObject(CacheConstants.TICKET_PRICE_LIST_KEY+sessionId,listVo,60*60, TimeUnit.SECONDS);
        }
        return listVo;
    }

    /**
     * 查询小程序座位信息 保留可售
     * @param sessionId
     * @return
     */
    @Override
    public List<SeatDetailVo> selectSeatVoDetailList(Long sessionId){
        return yanchuSeatMapper.selectSeatVoDetailList(sessionId);
    }

    @Override
    public Table<String, String, PriceSeatVo> selectPriceList(Long sessionId)
    {
        List<YanchuTicketPrice> list = yanchuTicketPriceMapper.selectPriceList(sessionId);
        if(CollectionUtils.isEmpty(list)){
            return null;
        }
        // <区，行，座位>
        Table<String, String, PriceSeatVo> seatTable = HashBasedTable.create();
        String seats = null,seat = null,xPosStrs = null;
        JSONArray jsonArray=null,jsonSeatsArray = null;
        JSONObject jsonObject = null,jsonSeatObject = null;
        Integer areaId = null;
        Integer row=null;
        PriceSeatVo priceSeatVo = null;
        for(YanchuTicketPrice price:list){
            seats = price.getSeats();
            if(StringUtils.isEmpty(seats)){
                continue;
            }
            jsonArray = JSONArray.parseArray(seats);
            for(int i=0;i<jsonArray.size();i++){
                jsonObject = jsonArray.getJSONObject(i);
                areaId = jsonObject.getInteger("areaId");
                jsonSeatsArray = jsonObject.getJSONArray("seats");
                for(int j=0;j<jsonSeatsArray.size();j++){
                    jsonSeatObject = jsonSeatsArray.getJSONObject(j);
                    row = jsonSeatObject.getInteger("row");
                    seat = jsonSeatObject.getString("seatNo");
                    xPosStrs = jsonSeatObject.getString("col");
                    if(StringUtils.isNotEmpty(seat)){
                        List<String> seatStrs = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(seat);
                        List<String> xPosList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(xPosStrs);
                        if(seatStrs.size() != xPosList.size()){
                            throw new ServiceException("发布失败");
                        }
                        for(int k=0;k<xPosList.size();k++){
                            priceSeatVo = new PriceSeatVo();
                            priceSeatVo.setxPos(Integer.valueOf(xPosList.get(k)));
                            priceSeatVo.setPriceId(price.getId());
                            priceSeatVo.setPrice(price.getSalePrice());
                            seatTable.put(areaId+"_"+row,xPosList.get(k),priceSeatVo);
                        }
                    }
                }
            }
        }
        return seatTable;
    }

    /**
     * 新增场次价格
     * 
     * @param yanchuTicketPrice 场次价格
     * @return 结果
     */
    @Override
    public int insertYanchuTicketPrice(YanchuTicketPrice yanchuTicketPrice)
    {
        LoginUser user = SecurityUtils.getLoginUser();
        yanchuTicketPrice.setCreateTime(DateUtils.getNowDate());
        yanchuTicketPrice.setCreateBy(user.getUserId()+"");
        //校验是否可新增
        Integer integer = yanchuSessionMapper.chackStatus(yanchuTicketPrice.getSessionId());
        if (integer <= 0){
            throw new BaseException("当前演出状态非创建中或取消,不可新增");
        }
        //校验当前场次下价格挡位名称是否重复
        if (chackTickName(null,yanchuTicketPrice.getSessionId(),yanchuTicketPrice.getTitle())){
            throw new BaseException("票档名称在该场次内已存在");
        }
        //校验当前场次下价格颜色是否重复
        if (chackTickColor(yanchuTicketPrice.getId(),yanchuTicketPrice.getSessionId(),yanchuTicketPrice.getColor())){
            throw new BaseException("票档颜色在该场次内已存在");
        }
        return yanchuTicketPriceMapper.insertYanchuTicketPrice(yanchuTicketPrice);
    }

    /**
     * 校验当前场次下价格颜色是否重复
     *
     * @param id
     * @param sessionId
     * @param color
     * @return
     */
    private Boolean chackTickColor(Long id, Long sessionId, String color) {
        List<YanchuTicketPrice> ticketPrices = yanchuTicketPriceMapper.selectPriceList(sessionId);
        if (CollectionUtils.isNotEmpty(ticketPrices)){
            for (YanchuTicketPrice ticketPrice : ticketPrices) {
                if (null == id){
                    if (color.equals(ticketPrice.getColor())){
                        return true;
                    }
                }else {
                    if (color.equals(ticketPrice.getColor()) && !id.equals(ticketPrice.getId())){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 校验当前场次下价格挡位名称是否重复
     *
     * @param id
     * @param sessionId
     * @param title
     * @return
     */
    private Boolean chackTickName(Long id, Long sessionId, String title) {
        List<YanchuTicketPrice> ticketPrices = yanchuTicketPriceMapper.selectPriceList(sessionId);
        if (CollectionUtils.isNotEmpty(ticketPrices)){
            for (YanchuTicketPrice ticketPrice : ticketPrices) {
                if (null == id){
                    if (title.equals(ticketPrice.getTitle())){
                        return true;
                    }
                }else {
                    if (title.equals(ticketPrice.getTitle()) && !id.equals(ticketPrice.getId())){
                        return true;
                    }
                }
            }
        }
        return false;
    }

    /**
     * 修改场次价格
     * 
     * @param yanchuTicketPrice 场次价格
     * @return 结果
     */
    @Override
    public int updateYanchuTicketPrice(YanchuTicketPrice yanchuTicketPrice)
    {
        //仅限演出场次为创建中和取消状态可以编辑  即演出场次表中status为0和3的可以编辑
        Integer integer = yanchuSessionMapper.chackStatus(yanchuTicketPrice.getSessionId());
        if (integer <= 0){
            throw new BaseException("当前演出状态非创建中或取消,不可编辑");
        }
        //校验当前场次下价格挡位名称是否重复
        if (chackTickName(yanchuTicketPrice.getId(),yanchuTicketPrice.getSessionId(),yanchuTicketPrice.getTitle())){
            throw new BaseException("票档名称在该场次内已存在");
        }
        //校验当前场次下价格颜色是否重复
        if (chackTickColor(yanchuTicketPrice.getId(),yanchuTicketPrice.getSessionId(),yanchuTicketPrice.getColor())){
            throw new BaseException("票档颜色在该场次内已存在");
        }
        yanchuTicketPrice.setUpdateTime(DateUtils.getNowDate());
        return yanchuTicketPriceMapper.updateYanchuTicketPrice(yanchuTicketPrice);
    }

    /**
     * 批量删除场次价格
     * 
     * @param ids 需要删除的场次价格主键
     * @return 结果
     */
    @Override
    public int deleteYanchuTicketPriceByIds(Long[] ids)
    {
        return yanchuTicketPriceMapper.deleteYanchuTicketPriceByIds(ids);
    }

    /**
     * 删除场次价格信息
     * 
     * @param id 场次价格主键
     * @return 结果
     */
    @Override
    public int deleteYanchuTicketPriceById(Long id)
    {
        //仅限演出场次为创建中和取消状态可以删除  即演出场次表中status为0和3的可以删除
        Integer integer = yanchuSessionMapper.chackDeleteStatus(id);
        if (integer <= 0){
            throw new BaseException("当前演出状态非创建中或取消,不可删除");
        }
        YanchuTicketPrice ticketPrice = yanchuTicketPriceMapper.selectYanchuTicketPriceById(id);
        if (null != ticketPrice && StringUtils.isNotEmpty(ticketPrice.getSeats())){
            List<String> keys = disposeSeat(ticketPrice.getSeats());
            //处理预留座
            List<String> ticketKey = disposeResSeat(ticketPrice.getSessionId());
            List<String> collect = ticketKey.stream().filter(keys::contains).collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(collect)){
                throw new BaseException("当前票档存在预留座,请先处理预留座");
            }
        }
        return yanchuTicketPriceMapper.deleteYanchuTicketPriceById(id);
    }


    public List<String> disposeSeat(String seats) {
        List<String> keys = new ArrayList<>();
        JSONArray seatArray = JSONArray.parseArray(seats);
        for (int i = 0; i < seatArray.size(); i++) {
            JSONObject jsonObject = seatArray.getJSONObject(i);
            Integer areaId = jsonObject.getInteger("areaId");
            JSONArray seatJsonArray = jsonObject.getJSONArray("seats");
            for (int j = 0; j < seatJsonArray.size(); j++) {
                JSONObject seatJson = seatJsonArray.getJSONObject(j);
                Long row = seatJson.getLong("row");//行
                String seatNos = seatJson.getString("seatNo");//座位号
                String cols = seatJson.getString("col");//坐标
                List<String> seatNoList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(seatNos);
                List<String> colNoList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(cols);
                if(CollectionUtils.isEmpty(seatNoList) || CollectionUtils.isEmpty(colNoList)){
                    continue;
                }
                String key = areaId+"-"+row+"-";
                for (int s = 0; s < seatNoList.size(); s++) {
                    keys.add(key.concat(seatNoList.get(s)).concat("-").concat(colNoList.get(s)));
                }
            }
        }
        return keys;
    }

    /**
     * 获取某场次下预留座座位
     *
     * @param sessionId
     * @return
     */
    public List<String> disposeResSeat(Long sessionId) {
        TYanchuReservedTicket ticket = new TYanchuReservedTicket();
        ticket.setSessionId(sessionId);
        List<TYanchuReservedTicket> tickets = yanchuReservedTicketMapper.selectTYanchuReservedTicketList(ticket);
        List<String> keys = new ArrayList<>();
        if (CollectionUtils.isNotEmpty(tickets)){
            tickets.forEach(t ->{
                String seats = t.getSeats();
                JSONArray seatArray = JSONArray.parseArray(seats);
                for (int i = 0; i < seatArray.size(); i++) {
                    JSONObject jsonObject = seatArray.getJSONObject(i);
                    Integer areaId = jsonObject.getInteger("areaId");
                    JSONArray seatJsonArray = jsonObject.getJSONArray("seats");
                    for (int j = 0; j < seatJsonArray.size(); j++) {
                        JSONObject seatJson = seatJsonArray.getJSONObject(j);
                        Long row = seatJson.getLong("row");//行
                        String seatNos = seatJson.getString("seatNo");//座位号
                        String cols = seatJson.getString("col");//坐标
                        List<String> seatNoList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(seatNos);
                        List<String> colNoList = Splitter.on(",").trimResults().omitEmptyStrings().splitToList(cols);
                        if(CollectionUtils.isEmpty(seatNoList) || CollectionUtils.isEmpty(colNoList)){
                            continue;
                        }
                        String key = areaId+"-"+row+"-";
                        for (int s = 0; s < seatNoList.size(); s++) {
                            keys.add(key.concat(seatNoList.get(s)).concat("-").concat(colNoList.get(s)));
                        }
                    }
                }
            });
        }
        return keys;
    }

    @Override
    public AjaxResult calcPrice(List<SeatVo> seatVos){
        if(CollectionUtils.isEmpty(seatVos)){
            return AjaxResult.error("必填信息不能为空！");
        }
        Map map = Maps.newHashMap();
        BigDecimal totalPrice = new BigDecimal(0);

        String key = CacheConstants.TICKET_LOCK_KEY + seatVos.get(0).getSessionId();
        String hKey = null;
        List<Object> keys = Lists.newArrayList();
        for(SeatVo seatVo:seatVos){
            hKey = seatVo.getAreaId()+"-"+seatVo.getRowNumber()+"-"+seatVo.getxPos();
            keys.add(hKey);
        }

        List<YanchuSeat> seatList = redisCache.getMultiCacheMapValue(key,keys);
        logger.info("keys:{} seatList:{}",keys,seatList);
        if(CollectionUtils.isEmpty(seatList) || seatList.size() != seatVos.size()){
            return AjaxResult.error("获取价格失败！");
        }
        for(YanchuSeat seat:seatList){
            if(null == seat){
                return AjaxResult.error("获取价格失败！");
            }
            totalPrice = totalPrice.add(seat.getMoney());
        }
        map.put("seatList",seatList);
        map.put("totalPrice",totalPrice);
        return AjaxResult.success(map);
    }

    /**
     * 处理票档价格座位及预留座座位处理
     *
     * @param ticketAndResVOs
     * @return
     */
    @Override
    @Transactional(rollbackFor = RuntimeException.class)
    public int disposeTickAndRes(List<TicketAndResVO> ticketAndResVOs) {
        Long sessionId = ticketAndResVOs.get(0).getSessionId();
        YanchuSession session = yanchuSessionMapper.selectYanchuSessionById(sessionId);
        if (Const.ZERO.equals(session.getStatus()) || Const.THREE.equals(session.getStatus()) || Const.TWO.equals(session.getStatus())){
            if (!Const.TWO.equals(session.getStatus())) {//非暂停销售
                this.tickPrice(ticketAndResVOs);
            }
            this.tickRes(ticketAndResVOs,session);
        }else {
            throw new BaseException("当前场次不是创建中或取消状态,不可编辑");
        }
        return 1;
    }

    private void tickPrice(List<TicketAndResVO> ticketAndResVOs){
        //将当前场次所有座位置空
        yanchuTicketPriceMapper.updateYanchuTicketPriceBy(ticketAndResVOs.get(0).getSessionId());
        //票档id
        List<Long> priceIds = ticketAndResVOs.stream().map(TicketAndResVO::getPriceId).distinct().collect(Collectors.toList());
        for (Long priceId : priceIds) {
            List<AreaJsonVO> vo = new ArrayList<>();
            List<TicketAndResVO> prices = ticketAndResVOs.stream().filter(t -> priceId.equals(t.getPriceId())).collect(Collectors.toList());
            List<Integer> areaIds = prices.stream().map(TicketAndResVO::getAreaId).distinct().collect(Collectors.toList());
            for (Integer areaId : areaIds) {
                AreaJsonVO areaJsonVO = new AreaJsonVO();
                List<TicketAndResVO> areas = prices.stream().filter(p -> areaId.equals(p.getAreaId())).collect(Collectors.toList());
                List<Integer> rows = areas.stream().map(TicketAndResVO::getRow).distinct().collect(Collectors.toList());
                List<SeatJsonVO> vos = new ArrayList<>();
                for (Integer row : rows) {
                    SeatJsonVO jsonVO = new SeatJsonVO();
                    List<Integer> seatNum = new ArrayList<>();
                    List<Integer> cols = new ArrayList<>();
                    for (TicketAndResVO area : areas) {
                        if (row.equals(area.getRow())){
                            seatNum.add(area.getSetNum());
                            cols.add(area.getCol());
                        }
                    }
                    jsonVO.setRow(row);
                    jsonVO.setSeatNo(Joiner.on(",").join(seatNum));
                    jsonVO.setCol(Joiner.on(",").join(cols));
                    vos.add(jsonVO);
                }
                areaJsonVO.setAreaId(areaId);
                areaJsonVO.setSeats(vos);
                vo.add(areaJsonVO);
            }
            YanchuTicketPrice price = new YanchuTicketPrice();
            price.setId(priceId);
            price.setSalable(1);
            price.setSeats(JSONObject.toJSONString(vo));
            yanchuTicketPriceMapper.updateYanchuTicketPrice(price);
        }
    }

    private void tickRes(List<TicketAndResVO> ticketAndResVOs,YanchuSession session){
        //删除原有预留座信息
        yanchuReservedTicketService.deleteBySessionId(session.getId());
        //预留座
        List<Long> resSeatIds = ticketAndResVOs.stream().filter(t -> t.getResSeatId() != null).map(TicketAndResVO::getResSeatId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(resSeatIds)){
            return;
        }
        List<SeatCompareVo> seatVos = new ArrayList<>();
        for (Long priceId : resSeatIds) {
            List<AreaJsonVO> vo = new ArrayList<>();
            List<TicketAndResVO> prices = ticketAndResVOs.stream().filter(t -> priceId.equals(t.getResSeatId())).collect(Collectors.toList());
            List<Integer> areaIds = prices.stream().map(TicketAndResVO::getAreaId).distinct().collect(Collectors.toList());
            for (Integer areaId : areaIds) {
                AreaJsonVO areaJsonVO = new AreaJsonVO();
                List<TicketAndResVO> areas = prices.stream().filter(p -> areaId.equals(p.getAreaId())).collect(Collectors.toList());
                List<Integer> rows = areas.stream().map(TicketAndResVO::getRow).distinct().collect(Collectors.toList());
                List<SeatJsonVO> vos = new ArrayList<>();
                for (Integer row : rows) {
                    SeatJsonVO jsonVO = new SeatJsonVO();
                    List<Integer> seatNum = new ArrayList<>();
                    List<Integer> cols = new ArrayList<>();
                    for (TicketAndResVO area : areas) {
                        if (row.equals(area.getRow())){
                            seatNum.add(area.getSetNum());
                            cols.add(area.getCol());
                            if(null != session.getStatus() && session.getStatus().equals(PerformConstants.SESSION_DOWN)){
                                seatVos.add(new SeatCompareVo(session.getId(),areaId,area.getRow(),area.getCol(),area.getResSeatId()));
                            }
                        }
                    }
                    jsonVO.setRow(row);
                    jsonVO.setSeatNo(Joiner.on(",").join(seatNum));
                    jsonVO.setCol(Joiner.on(",").join(cols));
                    vos.add(jsonVO);
                }
                areaJsonVO.setAreaId(areaId);
                areaJsonVO.setSeats(vos);
                vo.add(areaJsonVO);
            }
            TYanchuReservedTicket ticket = new TYanchuReservedTicket();
            ticket.setOperaId(session.getOperaId());
            ticket.setHallId(session.getHallId());
            ticket.setSessionId(session.getId());
            ticket.setPlanId(session.getPerformId());
            ticket.setResSeatId(priceId);
            ticket.setSeats(JSONObject.toJSONString(vo));
            ticket.setCreatTime(DateUtils.getNowDate());
            yanchuReservedTicketService.insertTYanchuReservedTicket(ticket);
        }
    }
}
